package com.gebiafu.service.impl;

import com.gebiafu.exception.DaoException;
import com.gebiafu.mapper.SystemFileMapper;
import com.gebiafu.mapper.UserMapper;
import com.gebiafu.pojo.SystemFile;
import com.gebiafu.pojo.User;
import com.gebiafu.service.FileUploadService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * title: FileUploadServiceImpl
 * author: Gebiafu
 * date: 2021/07/02 17:34
 */
@Service
public class FileUploadServiceImpl implements FileUploadService {
    @Autowired
    private SystemFileMapper systemFileMapper;
    @Autowired
    private UserMapper userMapper;
    //保存文件的文件夹路径
    private final String dir="E:\\fileManger";
    /**
     * 上传文件:
     * 1,随机生成文件名,注意不能丢失文件的后缀名
     * 2,把上传的文件,保存到本地硬盘中
     *  统一保存到文件夹D:/fileManger中
     *  保存的时候判断文件夹是否存在,不在则创建
     * 3,收集上传文件的相关数据,保存到数据库中
     * @param file
     * @return
     */
    @Override
    @Transactional(rollbackFor = {DaoException.class})
    public boolean uploadFile(MultipartFile file) {
        String randomFileName="";
        try {
            //获得文件的原始名
            String originalFilename = file.getOriginalFilename();
            //文件的后缀名变量
            String extName="";
            //获得文件后缀名
            if(originalFilename.indexOf(".")>=0){
                //文件原始名中含有字符"."
                extName=originalFilename.substring(originalFilename.lastIndexOf("."));
            }
            //生成一个随机字符串UUID,作为文件的随机名称
            randomFileName=UUID.randomUUID().toString()+ extName;
            System.out.println("生成的文件名"+randomFileName);
            //保存上传得文件到本地目录
            //判断文件夹是否存在,不在则创建
            File dir=new File(this.dir);
            if(!dir.exists()){
                //文件夹不存在,创建
                dir.mkdir();
            }
            //保存文件到本地
            //在文件夹dir中创建文件
            File persistFile = new File(dir,randomFileName);
            //保存文件到本地
            try{
                file.transferTo(persistFile);
            }catch (IOException e){
                //保存文件到本地失败/
                e.printStackTrace();
                return false;
            }
            //获得登陆用户的用户名
            String loginUserName=
            SecurityContextHolder//Security框架提供的上下文处理工具
                    .getContext()//获取一个请求对应的上下文对象,上下文对象是和线程相关的,使用ThreadLocal
                    .getAuthentication()//获取一个请求对应的登陆认证用户主体对象
                    .getName();//获得登陆用户的用户名
            //根据用户名查询用户对象
            User user = userMapper.selectUser(loginUserName);
            //获得用户的主键
            Long userId = user.getId();
            //创建上下文对应得实体类对象
            //处理文件大小(MB)
            long size = file.getSize()/1024/1024;
            SystemFile systemFile=new SystemFile(
                    null,
                    randomFileName,//随机名称
                    originalFilename,//原始名称
                    size,//文件大小
                    userId//登陆用户主键
            );
            System.out.println("新的文件"+systemFile);
            //保存到数据库
            int insert = systemFileMapper.insert(systemFile);
            System.out.println(insert);
            //判断是否新增成功
            if(insert!=1){
                throw new DaoException("新增文件到数据库发生错误");
            }
            //上传文件成功,保存文件相关数据到数据库成功
            return true;
        } catch (DaoException e) {
            this.uploadFileRollback(randomFileName);
            throw e;
        }catch (Exception e){
            this.uploadFileRollback(randomFileName);
            throw new DaoException("上传文件时,其他错误",e);
        }
    }

    /**
     * 分页查询文件
     * 条件是登陆用户的主键
     * @param page
     * @param rows
     * @return
     */
    @Override
    public Map<String, Object> getFileByPage(int page, int rows) {
        try {
            //获得登陆用户的主键
            //获得登陆用户的用户名
            String loginUserUsername = SecurityContextHolder.getContext().getAuthentication().getName();
            //查询用户
            User loginUser = userMapper.selectUser(loginUserUsername);
            //用户主键
            Long userId = loginUser.getId();
            //分页逻辑
            PageHelper.startPage(page, rows);
            //查询文件
            List<SystemFile> list = systemFileMapper.selectByUserId(userId);
            PageInfo<SystemFile> pageInfo = new PageInfo<>(list);
            //获取总页码
            int pages = pageInfo.getPages();
            //获取总数量
            long total = pageInfo.getTotal();
            //处理返回的结果
            Map<String, Object> map = new HashMap<>();
            map.put("pages", pages);//总页码
            map.put("currPage", page);//当前页码
            map.put("total", total);//总文件个数
            map.put("list", list);//当前页显示的文件集合
            return map;
        }catch(Exception e){
            throw new DaoException("查询错误",e);
        }
    }

    /**
     * 通过文件的名称,获得文件的内容
     * @param fileName
     * @return
     */
    @Override
    public byte[] getFile(String fileName) {
        //创建要读取的文件对象
        File file=new File(new File(dir),fileName);
        //创建io流
        FileInputStream inputStream=null;
        byte[] datas=null;
        try {
            inputStream=new FileInputStream(file);
            //创建字节数组
            datas=new byte[inputStream.available()];
            //读取文件内容,一次性把文件的所有数据读取到字节数组中;
            inputStream.read(datas,0,datas.length);
        } catch (Exception e) {
            e.printStackTrace();
            datas=null;//发生任何异常,则返回null
        }
        return datas;
    }

    /**
     * 当保存上传文件到本地硬盘后,数据库访问失败,需要删除上传保存的文件
     * @param fileName
     */
    private void uploadFileRollback(String fileName){
        File file=new File(new File(dir),fileName);
        if(file.exists()){
            //文件存在,删除
            file.delete();
        }
    }
}
